#if !defined(INDENTED_OUTPUT_FILTER_H)
#define INDENTED_OUTPUT_FILTER_H

#include <string>
	//using std::string
#include <sstream>
	//using std::ostringstream;
#include <boost/date_time/posix_time/posix_time.hpp>
	//using boost::posix_time::second_clock;

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/categories.hpp> // output tag
#include <boost/iostreams/operations.hpp> // put, write


namespace indent_streams
{
	namespace io = boost::iostreams;

	 struct filter_category
        : //io::seekable,
		 io::flushable_tag,
		 io::output
        { };
	
	template <typename INDENT_FUNC>
	class indent_output_filter : public io::filter<filter_category>
	{
	public:
		indent_output_filter(INDENT_FUNC indent_func_) : 
			indent_func(indent_func_),
			middle_of_line(false)
		{}
	
		template<typename Sink>
		bool flush(Sink& dest)
		{ return io::flush(dest);}


		template<typename Sink>
		bool put(Sink& dest, int c)
		{
			if (middle_of_line)
			{
				middle_of_line = (c != '\n');
				return io::put(dest, c);
			}

			//
			//  Start of line
			// 

			std::string indent_str  = indent_func();
			//
			//	output indent at beginning of lines 
			// 
			if (indent_str.length() && 
				static_cast<std::streamsize>(indent_str.length()) != io::write(dest,&indent_str[0], indent_str.length()))
				return false;

			middle_of_line = (c != '\n');
			if (!io::put(dest, c))
				return false;
			if (!io::flush(dest))
				return false;
			return true;
		}

	
	private:
		INDENT_FUNC indent_func;
		bool middle_of_line;
	};
	
	

	struct indent_with_prefix
	{
		std::string prefix;
		std::string operator()() const{return prefix;}
		indent_with_prefix(const std::string& prefix_): prefix(prefix_){}
	};
	struct indent_with_prefix_and_timestamp
	{
		std::string prefix;
		std::string operator()() const
		{
			std::ostringstream ss;
			ss << boost::posix_time::second_clock::local_time();
			return ss.str() + " " + prefix;
		}
		indent_with_prefix_and_timestamp(const std::string& prefix_): prefix(prefix_.length() ? (prefix_ + " ") : prefix_){}
	};

	typedef indent_output_filter<indent_with_prefix_and_timestamp> indent_with_prefix_and_timestamp_output_filter;
	typedef indent_output_filter<indent_with_prefix> indent_with_prefix_output_filter;
}



//indent_OUTPUT_FILTER_H
#endif
